/*
-----------------------------------------------------------------------------
This source file is part of SapphireEngine

SapphireEngine is a Framework for Turn Based Strategy games.
For more information see http://code.google.com/p/sapphire-engine/

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

-----------------------------------------------------------------------------
*/
#ifndef _GUI_MANAGER_H
#define _GUI_MANAGER_H

#include "SapphirePrerequisites.h"

#include <CEGUI/CEGUI.h>
#include <OIS/OIS.h>
#include <OgreCEGUIRenderer.h>

#include "GUI/Screens.h"
#include "SapphireMemoryManager.h"

namespace SapphireEngine
{
	namespace GUI
	{
		class GUIManager :public Ogre::Singleton<GUIManager>
		{
		public:
			GUIManager(): mSystem(0), mRenderer(0)
			{
			}

			~GUIManager() 
			{
				if (mSystem)
				{
					getMemoryManager()->removePointer(mSystem);
					delete mSystem;
				}

				if (mRenderer)
				{
					getMemoryManager()->removePointer(mRenderer);
					delete mRenderer;
				}

				for (ScreenMapConstIterator itr=mScreens.begin();itr!=mScreens.end();itr++)
				{
					getMemoryManager()->removePointer(itr->second);
					delete itr->second;
				}
				mScreens.clear();

			}

			bool init()
			{
				Ogre::SceneManager *mgr = Ogre::Root::getSingletonPtr()->getSceneManager("Default SceneManager");
				Ogre::RenderWindow *win = Ogre::Root::getSingletonPtr()->getAutoCreatedWindow();

				// CEGUI setup
				mRenderer = new CEGUI::OgreCEGUIRenderer(win, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, mgr);
				getMemoryManager()->addPointer(mRenderer,"Renderer");
				mSystem = new CEGUI::System(mRenderer);
				getMemoryManager()->addPointer(mSystem,"System");

				// CEGUI Scheme
				//CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"SleekSpace.scheme");
				CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLookSkin.scheme");

				//CEGUI Defaults
				mSystem->setDefaultMouseCursor((CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow");
				mSystem->setDefaultFont((CEGUI::utf8*)"BlueHighway-12");
				CEGUI::MouseCursor::getSingleton().setImage(CEGUI::System::getSingleton().getDefaultMouseCursor());

				return true;
			}

			OgreCEGUIRenderer* getRenderer()
			{
				return mRenderer;
			}

// 			CEGUI::System* getSystem()
// 			{
// 				return mSystem;
// 			}

			void setActiveLayout(Window* layout)
			{
				mSystem->setGUISheet(layout);
			}
			void setMouseCursor(char* img=0)
			{
				if(!img)
					MouseCursor::getSingleton().setImage(System::getSingleton().getDefaultMouseCursor());
				else
					MouseCursor::getSingleton().setImage((CEGUI::Image*)img);
			}

			// KeyListener
			void GUIkeyPressed(const OIS::KeyEvent &arg)
			{
				mSystem->injectKeyDown(arg.key);
				mSystem->injectChar(arg.text);
			}
			void GUIkeyReleased(const OIS::KeyEvent &arg)
			{
				mSystem->injectKeyUp(arg.key); 
			}

			// MouseListener
			void GUImouseMoved(const OIS::MouseEvent &arg) 
			{
				mSystem->injectMouseMove(arg.state.X.rel, arg.state.Y.rel);
			}
			void GUImousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
			{ 
				mSystem->injectMouseButtonDown(convertButton(id));
			}
			void GUImouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) 
			{
				mSystem->injectMouseButtonUp(convertButton(id));
			}

			//Screens
			void addScreen(Ogre::String name, Screen* pScreen)
			{
				mScreens.insert(ScreenMapItem(name,pScreen));
				if(mScreens.size() == 1)
					mCurrentScreen = mScreens.begin();
			}
			void removeScreen(Ogre::String name)
			{
				mScreens.erase(name);
			}
			Screen* getScreen(Ogre::String screen)
			{
				return mScreens.find(screen)->second;
			}
			Screen* getCurrentScreen()
			{
				return mCurrentScreen->second;
			}
			void setScreen(Ogre::String name)
			{
				mCurrentScreen->second->unSubscribeEvents();
				mCurrentScreen = mScreens.find(name);
				mCurrentScreen->second->showLayout();

			}
			static GUIManager& getSingleton(void);
			static GUIManager* getSingletonPtr(void);
		private:
			MouseButton convertButton(OIS::MouseButtonID buttonID)
			{
				switch (buttonID)
				{
				case OIS::MB_Left:
					return LeftButton;

				case OIS::MB_Right:
					return RightButton;

				case OIS::MB_Middle:
					return MiddleButton;

				default:
					return LeftButton;
				}
			}

			System *mSystem;
			OgreCEGUIRenderer *mRenderer;
			ScreenMapConstIterator mCurrentScreen;
			ScreenMap mScreens;
		};

		class ScreenListener :public FrameListener, public OIS::MouseListener, public OIS::KeyListener, Ogre::Singleton<ScreenListener>
		{
		public:
			ScreenListener(OIS::Keyboard *keyboard, OIS::Mouse *mouse):mKeyboard(keyboard),mMouse(mouse)
			{	
				//mContinue=true;
				mMouse->setEventCallback(this);
				mKeyboard->setEventCallback(this);
			}
			bool frameStarted(const FrameEvent &evt)
			{
				mKeyboard->capture();
				mMouse->capture();
				Ogre::String nextScreenName = getGUIManager()->getCurrentScreen()->getNextScreenName();
				if (nextScreenName.compare("")!=0)
					getGUIManager()->setScreen(nextScreenName);

				return getGUIManager()->getCurrentScreen()->update(evt);
				//return mContinue;
			}

			// MouseListener
			bool mouseMoved(const OIS::MouseEvent &arg)
			{
				getGUIManager()->GUImouseMoved(arg);
				getGUIManager()->getCurrentScreen()->mouseMoved(arg);
				return true;
			}

			bool mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
			{
				getGUIManager()->GUImousePressed(arg,id);
				getGUIManager()->getCurrentScreen()->mousePressed(arg,id);
				return true;
			}

			bool mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id)
			{
				getGUIManager()->GUImouseReleased(arg,id);
				getGUIManager()->getCurrentScreen()->mouseReleased(arg,id);
				return true;
			}

			// KeyListener
			bool keyPressed(const OIS::KeyEvent &arg)
			{
				getGUIManager()->GUIkeyPressed(arg);
				getGUIManager()->getCurrentScreen()->keyPressed(arg);
				return true;
			}

			bool keyReleased(const OIS::KeyEvent &arg)
			{
				getGUIManager()->GUIkeyReleased(arg);
				getGUIManager()->getCurrentScreen()->keyReleased(arg);
				return true;
			}

			static ScreenListener& getSingleton(void);
			static ScreenListener* getSingletonPtr(void);
		protected:
			//bool mContinue;
			OIS::Keyboard *mKeyboard;
			OIS::Mouse *mMouse;
		};
	}
}
using SapphireEngine::GUI::GUIManager;
//GUIManager template
template<> GUIManager* Ogre::Singleton<GUIManager>::ms_Singleton = 0;
GUIManager* GUIManager::getSingletonPtr(void)
{
    return ms_Singleton;
}
GUIManager& GUIManager::getSingleton(void)
{  
    assert( ms_Singleton );  return ( *ms_Singleton );  
}

using SapphireEngine::GUI::ScreenListener;
//ScreenListener template
template<> ScreenListener* Ogre::Singleton<ScreenListener>::ms_Singleton = 0;
ScreenListener* ScreenListener::getSingletonPtr(void)
{
	return ms_Singleton;
}
ScreenListener& ScreenListener::getSingleton(void)
{  
	assert( ms_Singleton );  return ( *ms_Singleton );  
}


#endif